home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / DistUpgrade / DistUpgradeViewKDE3.py < prev    next >
Text File  |  2009-11-02  |  29KB  |  714 lines

  1. # DistUpgradeViewKDE.py 
  2. #  
  3. #  Copyright (c) 2007 Canonical Ltd
  4. #  
  5. #  Author: Jonathan Riddell <jriddell@ubuntu.com>
  6. #  This program is free software; you can redistribute it and/or 
  7. #  modify it under the terms of the GNU General Public License as 
  8. #  published by the Free Software Foundation; either version 2 of the
  9. #  License, or (at your option) any later version.
  10. #  This program is distributed in the hope that it will be useful,
  11. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. #  GNU General Public License for more details.
  14. #  You should have received a copy of the GNU General Public License
  15. #  along with this program; if not, write to the Free Software
  16. #  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  17. #  USA
  18. #
  19. # THIS FRONTEND IS DEPRECATED IN FAVOR OF THE KDE4 ONE
  20. #
  21.  
  22. from qt import *
  23. from kdeui import *
  24. from kdecore import *
  25. from kio import KRun
  26. #from dcopext import DCOPClient, DCOPApp # used to quit adept
  27.  
  28. import sys
  29. import logging
  30. import time
  31. import subprocess
  32. import traceback
  33. import tempfile
  34.  
  35. import apt
  36. import apt_pkg
  37. import os
  38. import shutil
  39.  
  40. import pty
  41.  
  42. from DistUpgradeApport import *
  43.  
  44. from DistUpgradeController import DistUpgradeController
  45. from DistUpgradeView import DistUpgradeView, FuzzyTimeToStr, InstallProgress, FetchProgress
  46. from window_main import window_main
  47. from dialog_error import dialog_error
  48. from dialog_changes import dialog_changes
  49. from dialog_conffile import dialog_conffile
  50. from crashdialog import CrashDialog
  51.  
  52. import pty
  53. import select
  54. import gettext
  55. from gettext import gettext as gett
  56.  
  57. def _(str):
  58.     return unicode(gett(str), 'UTF-8')
  59.  
  60. def utf8(str):
  61.   if isinstance(str, unicode):
  62.       return str
  63.   return unicode(str, 'UTF-8')
  64.  
  65. class DumbTerminal(QTextEdit):
  66.     " a very dumb terminal "
  67.     def __init__(self, installProgress, parent_frame):
  68.         " really dumb terminal with simple editing support "
  69.         QTextEdit.__init__(self, "","", parent_frame)
  70.         self.installProgress = installProgress
  71.         self.setFamily("Monospace")
  72.         self.setPointSize(8)
  73.         self.setWordWrap(QTextEdit.NoWrap)
  74.         self.setUndoDepth(0)
  75.         self.setUndoRedoEnabled(False)
  76.         self._block = False
  77.         self.connect(self, SIGNAL("cursorPositionChanged(int,int)"), 
  78.                      self.onCursorPositionChanged)
  79.     def insertWithTermCodes(self, text):
  80.         " support basic terminal codes "
  81.         display_text = ""
  82.         for c in text:
  83.             # \b - backspace
  84.             if c == chr(8):       
  85.                 self.moveCursor(QTextEdit.MoveBackward, True)
  86.                 self.removeSelectedText()
  87.             # \r - is filtered out
  88.             elif c == chr(13):
  89.                 pass
  90.             # \a - bell - ignore for now
  91.             elif c == chr(7):
  92.                 pass
  93.             else:
  94.                 display_text += c
  95.         self.insert(display_text)
  96.     def keyPressEvent(self, ev):
  97.         " send (ascii) key events to the pty "
  98.         # FIXME: use ev.text() here instead and deal with
  99.         # that it sends strange stuff
  100.         if hasattr(self.installProgress,"master_fd"):
  101.             os.write(self.installProgress.master_fd, chr(ev.ascii()))
  102.     def onCursorPositionChanged(self, x, y):
  103.         " helper that ensures that the cursor is always at the end "
  104.         if self._block:
  105.             return
  106.         # block signals so that we do not run into a recursion
  107.         self._block = True
  108.         para = self.paragraphs() - 1
  109.         pos = self.paragraphLength(para)
  110.         self.setCursorPosition(para, pos)
  111.         self._block = False
  112.         
  113.  
  114. class KDECdromProgressAdapter(apt.progress.CdromProgress):
  115.     """ Report the cdrom add progress """
  116.     def __init__(self, parent):
  117.         self.status = parent.window_main.label_status
  118.         self.progressbar = parent.window_main.progressbar_cache
  119.         self.parent = parent
  120.  
  121.     def update(self, text, step):
  122.         """ update is called regularly so that the gui can be redrawn """
  123.         if text:
  124.           self.status.setText(text)
  125.         self.progressbar.setProgress(step/float(self.totalSteps))
  126.         KApplication.kApplication().processEvents()
  127.  
  128.     def askCdromName(self):
  129.         return (False, "")
  130.  
  131.     def changeCdrom(self):
  132.         return False
  133.  
  134. class KDEOpProgress(apt.progress.OpProgress):
  135.   """ methods on the progress bar """
  136.   def __init__(self, progressbar, progressbar_label):
  137.       self.progressbar = progressbar
  138.       self.progressbar_label = progressbar_label
  139.       #self.progressbar.set_pulse_step(0.01)
  140.       #self.progressbar.pulse()
  141.  
  142.   def update(self, percent):
  143.       #if percent > 99:
  144.       #    self.progressbar.set_fraction(1)
  145.       #else:
  146.       #    self.progressbar.pulse()
  147.       #self.progressbar.set_fraction(percent/100.0)
  148.       self.progressbar.setProgress(percent)
  149.       KApplication.kApplication().processEvents()
  150.  
  151.   def done(self):
  152.       self.progressbar_label.setText("")
  153.  
  154. class KDEFetchProgressAdapter(FetchProgress):
  155.     """ methods for updating the progress bar while fetching packages """
  156.     # FIXME: we really should have some sort of "we are at step"
  157.     # xy in the gui
  158.     # FIXME2: we need to thing about mediaCheck here too
  159.     def __init__(self, parent):
  160.         FetchProgress.__init__(self)
  161.         # if this is set to false the download will cancel
  162.         self.status = parent.window_main.label_status
  163.         self.progress = parent.window_main.progressbar_cache
  164.         self.parent = parent
  165.  
  166.     def mediaChange(self, medium, drive):
  167.       msg = _("Please insert '%s' into the drive '%s'") % (medium,drive)
  168.       change = QMessageBox.question(self.parent.window_main, _("Media Change"), msg, QMessageBox.Ok, QMessageBox.Cancel)
  169.       if change == QMessageBox.Ok:
  170.         return True
  171.       return False
  172.  
  173.     def start(self):
  174.         #self.progress.show()
  175.         self.progress.setProgress(0)
  176.         self.status.show()
  177.  
  178.     def stop(self):
  179.         self.parent.window_main.progress_text.setText("  ")
  180.         self.status.setText(_("Fetching is complete"))
  181.  
  182.     def pulse(self):
  183.         """ we don't have a mainloop in this application, we just call processEvents here and elsewhere"""
  184.         # FIXME: move the status_str and progress_str into python-apt
  185.         # (python-apt need i18n first for this)
  186.         FetchProgress.pulse(self)
  187.         self.progress.setProgress(self.percent)
  188.         currentItem = self.currentItems + 1
  189.         if currentItem > self.totalItems:
  190.             currentItem = self.totalItems
  191.  
  192.         if self.currentCPS > 0:
  193.             self.status.setText(_("Fetching file %li of %li at %sb/s") % (currentItem, self.totalItems, apt_pkg.SizeToStr(self.currentCPS)))
  194.             self.parent.window_main.progress_text.setText("<i>" + _("About %s remaining") % unicode(FuzzyTimeToStr(self.eta), 'utf-8') + "</i>")
  195.         else:
  196.             self.status.setText(_("Fetching file %li of %li") % (currentItem, self.totalItems))
  197.             self.parent.window_main.progress_text.setText("  ")
  198.  
  199.         KApplication.kApplication().processEvents()
  200.         return True
  201.  
  202. class KDEInstallProgressAdapter(InstallProgress):
  203.     """methods for updating the progress bar while installing packages"""
  204.     # timeout with no status change when the terminal is expanded
  205.     # automatically
  206.     TIMEOUT_TERMINAL_ACTIVITY = 240
  207.  
  208.     def __init__(self,parent):
  209.         InstallProgress.__init__(self)
  210.         self._cache = None
  211.         self.label_status = parent.window_main.label_status
  212.         self.progress = parent.window_main.progressbar_cache
  213.         self.progress_text = parent.window_main.progress_text
  214.         self.parent = parent
  215.         try:
  216.             self._terminal_log = open("/var/log/dist-upgrade/term.log","w")
  217.         except Exception, e:
  218.             # if something goes wrong (permission denied etc), use stdout
  219.             logging.error("Can not open terminal log: '%s'" % e)
  220.             self._terminal_log = sys.stdout
  221.         # some options for dpkg to make it die less easily
  222.         apt_pkg.Config.Set("DPkg::StopOnError","False")
  223.  
  224.     def startUpdate(self):
  225.         InstallProgress.startUpdate(self)
  226.         self.finished = False
  227.         # FIXME: add support for the timeout
  228.         # of the terminal (to display something useful then)
  229.         # -> longer term, move this code into python-apt 
  230.         self.label_status.setText(_("Applying changes"))
  231.         self.progress.setProgress(0)
  232.         self.progress_text.setText(" ")
  233.         # do a bit of time-keeping
  234.         self.start_time = 0.0
  235.         self.time_ui = 0.0
  236.         self.last_activity = 0.0
  237.         self.parent.window_main.showTerminalButton.setEnabled(True)
  238.  
  239.     def error(self, pkg, errormsg):
  240.         InstallProgress.error(self, pkg, errormsg)
  241.         logging.error("got an error from dpkg for pkg: '%s': '%s'" % (pkg, errormsg))
  242.     # we do not report followup errors from earlier failures
  243.         if gettext.dgettext('dpkg', "dependency problems - leaving unconfigured") in errormsg:
  244.       return False
  245.         summary = _("Could not install '%s'") % pkg
  246.         msg = _("The upgrade will continue but the '%s' package may not "
  247.                 "be in a working state. Please consider submitting a "
  248.                 "bug report about it.") % pkg
  249.         msg = "<big><b>%s</b></big><br />%s" % (summary, msg)
  250.         dialogue = dialog_error(self.parent.window_main)
  251.         dialogue.label_error.setText(utf8(msg))
  252.         if errormsg != None:
  253.             dialogue.textview_error.setText(utf8(errormsg))
  254.             dialogue.textview_error.show()
  255.         else:
  256.             dialogue.textview_error.hide()
  257.         dialogue.connect(dialogue.button_bugreport, SIGNAL("clicked()"), self.parent.reportBug)
  258.         dialogue.exec_loop()
  259.  
  260.     def conffile(self, current, new):
  261.         """ask question in case conffile has been changed by user"""
  262.         logging.debug("got a conffile-prompt from dpkg for file: '%s'" % current)
  263.         start = time.time()
  264.         prim = _("Replace the customized configuration file\n'%s'?") % current
  265.         sec = _("You will lose any changes you have made to this "
  266.                 "configuration file if you choose to replace it with "
  267.                 "a newer version.")
  268.         markup = "<span weight=\"bold\" size=\"larger\">%s </span> \n\n%s" % (prim, sec)
  269.         self.confDialogue = dialog_conffile(self.parent.window_main)
  270.         self.confDialogue.label_conffile.setText(markup)
  271.         self.confDialogue.textview_conffile.hide()
  272.         #FIXME, below to be tested
  273.         #self.confDialogue.resize(self.confDialogue.minimumSizeHint())
  274.         self.confDialogue.connect(self.confDialogue.show_difference_button, SIGNAL("clicked()"), self.showConffile)
  275.  
  276.         # now get the diff
  277.         if os.path.exists("/usr/bin/diff"):
  278.           cmd = ["/usr/bin/diff", "-u", current, new]
  279.           diff = utf8(subprocess.Popen(cmd, stdout=subprocess.PIPE).communicate()[0])
  280.           self.confDialogue.textview_conffile.setText(diff)
  281.         else:
  282.           self.confDialogue.textview_conffile.setText(_("The 'diff' command was not found"))
  283.         result = self.confDialogue.exec_loop()
  284.         self.time_ui += time.time() - start
  285.         # if replace, send this to the terminal
  286.         if result == QDialog.Accepted:
  287.             os.write(self.master_fd, "y\n")
  288.         else:
  289.             os.write(self.master_fd, "n\n")
  290.  
  291.     def showConffile(self):
  292.         if self.confDialogue.textview_conffile.isVisible():
  293.             self.confDialogue.textview_conffile.hide()
  294.             self.confDialogue.show_difference_button.setText(_("Show Difference >>>"))
  295.         else:
  296.             self.confDialogue.textview_conffile.show()
  297.             self.confDialogue.show_difference_button.setText(_("<<< Hide Difference"))
  298.        
  299.  
  300.     def fork(self):
  301.         """pty voodoo"""
  302.         (self.child_pid, self.master_fd)  = pty.fork()
  303.         if self.child_pid == 0:
  304.             os.environ["TERM"] = "dumb"
  305.             if not os.environ.has_key("DEBIAN_FRONTEND"):
  306.                 os.environ["DEBIAN_FRONTEND"] = "kde"
  307.             os.environ["APT_LISTCHANGES_FRONTEND"] = "none"
  308.         logging.debug(" fork pid is: %s" % self.child_pid)
  309.         return self.child_pid
  310.  
  311.     def statusChange(self, pkg, percent, status):
  312.         """update progress bar and label"""
  313.         # start the timer when the first package changes its status
  314.         if self.start_time == 0.0:
  315.           #print "setting start time to %s" % self.start_time
  316.           self.start_time = time.time()
  317.         self.progress.setProgress(self.percent)
  318.         self.label_status.setText(unicode(status.strip(), 'UTF-8'))
  319.         # start showing when we gathered some data
  320.         if percent > 1.0:
  321.           self.last_activity = time.time()
  322.           self.activity_timeout_reported = False
  323.           delta = self.last_activity - self.start_time
  324.           # time wasted in conffile questions (or other ui activity)
  325.           delta -= self.time_ui
  326.           time_per_percent = (float(delta)/percent)
  327.           eta = (100.0 - self.percent) * time_per_percent
  328.           # only show if we have some sensible data (60sec < eta < 2days)
  329.           if eta > 61.0 and eta < (60*60*24*2):
  330.             self.progress_text.setText(_("About %s remaining") % FuzzyTimeToStr(eta))
  331.           else:
  332.             self.progress_text.setText(" ")
  333.  
  334.     def finishUpdate(self):
  335.         self.label_status.setText("")
  336.  
  337.     def updateInterface(self):
  338.         """
  339.         no mainloop in this application, just call processEvents lots here
  340.         it's also important to sleep for a minimum amount of time
  341.         """
  342.         # log the output of dpkg (on the master_fd) to the terminal log
  343.         while True:
  344.             try:
  345.                 (rlist, wlist, xlist) = select.select([self.master_fd],[],[], 0)
  346.                 if len(rlist) > 0:
  347.                     line = os.read(self.master_fd, 255)
  348.                     self._terminal_log.write(line)
  349.                     self.parent.terminal_text.insertWithTermCodes(utf8(line))
  350.                 else:
  351.                     break
  352.             except Exception, e:
  353.                 print e
  354.                 logging.debug("error reading from self.master_fd '%s'" % e)
  355.                 break
  356.  
  357.         # now update the GUI
  358.         try:
  359.           InstallProgress.updateInterface(self)
  360.         except ValueError, e:
  361.           logging.error("got ValueError from InstallProgress.updateInterface. Line was '%s' (%s)" % (self.read, e))
  362.           # reset self.read so that it can continue reading and does not loop
  363.           self.read = ""
  364.         # check about terminal activity
  365.         if self.last_activity > 0 and \
  366.            (self.last_activity + self.TIMEOUT_TERMINAL_ACTIVITY) < time.time():
  367.           if not self.activity_timeout_reported:
  368.             #FIXME bug 95465, I can't recreate this, so here's a hacky fix
  369.             try:
  370.                 logging.warning("no activity on terminal for %s seconds (%s)" % (self.TIMEOUT_TERMINAL_ACTIVITY, self.label_status.text()))
  371.             except UnicodeEncodeError:
  372.                 logging.warning("no activity on terminal for %s seconds" % (self.TIMEOUT_TERMINAL_ACTIVITY))
  373.             self.activity_timeout_reported = True
  374.           self.parent.window_main.konsole_frame.show()
  375.         KApplication.kApplication().processEvents()
  376.         time.sleep(0.02)
  377.  
  378.     def waitChild(self):
  379.         while True:
  380.             self.updateInterface()
  381.             (pid, res) = os.waitpid(self.child_pid,os.WNOHANG)
  382.             if pid == self.child_pid:
  383.                 break
  384.         return os.WEXITSTATUS(res)
  385.  
  386. # inherit from the class created in window_main.ui
  387. # to add the handler for closing the window
  388. class UpgraderMainWindow(window_main):
  389.  
  390.     def setParent(self, parentRef):
  391.         self.parent = parentRef
  392.  
  393.     def closeEvent(self, event):
  394.         close = self.parent.on_window_main_delete_event()
  395.         if close:
  396.           event.accept()
  397.  
  398. class DistUpgradeViewKDE(DistUpgradeView):
  399.     """KDE frontend of the distUpgrade tool"""
  400.     def __init__(self, datadir=None, logdir=None):
  401.         if not datadir:
  402.           localedir=os.path.join(os.getcwd(),"mo")
  403.         else:
  404.           localedir="/usr/share/locale/update-manager"
  405.  
  406.         # FIXME: i18n must be somewhere relative do this dir
  407.         try:
  408.           gettext.bindtextdomain("update-manager", localedir)
  409.           gettext.textdomain("update-manager")
  410.         except Exception, e:
  411.           logging.warning("Error setting locales (%s)" % e)
  412.  
  413.         about=KAboutData("adept_manager","Upgrader","0.1","Dist Upgrade Tool for Kubuntu",KAboutData.License_GPL,"(c) 2007 Canonical Ltd",
  414.         "http://wiki.kubuntu.org/KubuntuUpdateManager", "jriddell@ubuntu.com")
  415.         about.addAuthor("Jonathan Riddell", None,"jriddell@ubuntu.com")
  416.         about.addAuthor("Michael Vogt", None,"michael.vogt@ubuntu.com")
  417.         KCmdLineArgs.init(["./dist-upgrade.py"],about)
  418.  
  419.         self.app = KApplication()
  420.  
  421.         self.window_main = UpgraderMainWindow()
  422.         self.window_main.setParent(self)
  423.         self.window_main.show()
  424.  
  425.         self.prev_step = 0 # keep a record of the latest step
  426.  
  427.         self._opCacheProgress = KDEOpProgress(self.window_main.progressbar_cache, self.window_main.progress_text)
  428.         self._fetchProgress = KDEFetchProgressAdapter(self)
  429.         self._cdromProgress = KDECdromProgressAdapter(self)
  430.  
  431.         self._installProgress = KDEInstallProgressAdapter(self)
  432.  
  433.         # reasonable fault handler
  434.         sys.excepthook = self._handleException
  435.  
  436.         ###self.window_main.showTerminalButton.setEnabled(False)
  437.         self.app.connect(self.window_main.showTerminalButton, SIGNAL("clicked()"), self.showTerminal)
  438.  
  439.         #kdesu requires us to copy the xauthority file before it removes it when Adept is killed
  440.         copyXauth = tempfile.mktemp("", "adept")
  441.         if 'XAUTHORITY' in os.environ and os.environ['XAUTHORITY'] != copyXauth:
  442.             shutil.copy(os.environ['XAUTHORITY'], copyXauth)
  443.             os.environ["XAUTHORITY"] = copyXauth
  444.  
  445.         # Note that with kdesudo this needs --nonewdcop
  446.         ## create a new DCOP-Client:
  447.         #client = DCOPClient()
  448.         ## connect the client to the local DCOP-server:
  449.         #client.attach()
  450.  
  451.         #for qcstring_app in client.registeredApplications():
  452.         #    app = str(qcstring_app)
  453.         #    if app.startswith("adept"): 
  454.         #        adept = DCOPApp(qcstring_app, client)
  455.         #        adeptInterface = adept.object("MainApplication-Interface")
  456.         #        adeptInterface.quit()
  457.  
  458.         # This works just as well
  459.         subprocess.call(["killall", "adept_manager"])
  460.         subprocess.call(["killall", "adept_updater"])
  461.  
  462.         # init gettext
  463.         gettext.bindtextdomain("update-manager",localedir)
  464.         gettext.textdomain("update-manager")
  465.         self.translate_widget_children()
  466.         self.window_main.label_title.setText(self.window_main.label_title.text().replace("Ubuntu", "Kubuntu"))
  467.  
  468.         # setup terminal text in hidden by default spot
  469.         self.window_main.konsole_frame.hide()
  470.         self.konsole_frame_layout = QHBoxLayout(self.window_main.konsole_frame)
  471.         self.window_main.konsole_frame.setMinimumSize(600, 400)
  472.         self.terminal_text = DumbTerminal(self._installProgress, 
  473.                                           self.window_main.konsole_frame)
  474.         self.konsole_frame_layout.addWidget(self.terminal_text)
  475.         self.terminal_text.show()
  476.         
  477.         # for some reason we need to start the main loop to get everything displayed
  478.         # this app mostly works with processEvents but run main loop briefly to keep it happily displaying all widgets
  479.         QTimer.singleShot(10, self.exitMainLoop)
  480.         self.app.exec_loop()
  481.         
  482.     def exitMainLoop(self):
  483.         self.app.exit()
  484.  
  485.     def translate_widget_children(self, parentWidget=None):
  486.         if parentWidget == None:
  487.             parentWidget = self.window_main
  488.  
  489.         if parentWidget.children() != None:
  490.             for widget in parentWidget.children():
  491.                 self.translate_widget(widget)
  492.                 self.translate_widget_children(widget)
  493.  
  494.     def translate_widget(self, widget):
  495.         if isinstance(widget, QLabel) or isinstance(widget, QPushButton):
  496.             if str(widget.text()) != "":
  497.                 widget.setText(_(str(widget.text())))
  498.  
  499.     def _handleException(self, exctype, excvalue, exctb):
  500.         """Crash handler."""
  501.  
  502.         if (issubclass(exctype, KeyboardInterrupt) or
  503.             issubclass(exctype, SystemExit)):
  504.             return
  505.  
  506.         # we handle the exception here, hand it to apport and run the
  507.         # apport gui manually after it because we kill u-m during the upgrade
  508.         # to prevent it from popping up for reboot notifications or FF restart
  509.         # notifications or somesuch
  510.         lines = traceback.format_exception(exctype, excvalue, exctb)
  511.         logging.error("not handled exception in KDE frontend:\n%s" % "\n".join(lines))
  512.         # we can't be sure that apport will run in the middle of a upgrade
  513.         # so we still show a error message here
  514.         apport_crash(exctype, excvalue, exctb)
  515.         if not run_apport():
  516.             tbtext = ''.join(traceback.format_exception(exctype, excvalue, exctb))
  517.             dialog = CrashDialog(self.window_main)
  518.             dialog.connect(dialog.beastie_url, SIGNAL("leftClickedURL(const QString&)"), self.openURL)
  519.             dialog.crash_detail.setText(tbtext)
  520.             dialog.exec_loop()
  521.         sys.exit(1)
  522.  
  523.     def openURL(self, url):
  524.         """start konqueror"""
  525.         #need to run this else kdesu can't run Konqueror
  526.         #subprocess.call(['su', 'ubuntu', 'xhost', '+localhost'])
  527.         KRun.runURL(KURL(url), "text/html")
  528.  
  529.     def reportBug(self):
  530.         """start konqueror"""
  531.         #need to run this else kdesu can't run Konqueror
  532.         #subprocess.call(['su', 'ubuntu', 'xhost', '+localhost'])
  533.         KRun.runURL(KURL("https://launchpad.net/distros/ubuntu/+source/update-manager/+filebug"), "text/html")
  534.  
  535.     def showTerminal(self):
  536.         if self.window_main.konsole_frame.isVisible():
  537.             self.window_main.konsole_frame.hide()
  538.             self.window_main.showTerminalButton.setText(_("Show Terminal >>>"))
  539.         else:
  540.             self.window_main.konsole_frame.show()
  541.             self.window_main.showTerminalButton.setText(_("<<< Hide Terminal"))
  542.         self.window_main.resize(self.window_main.sizeHint())
  543.  
  544.     def getFetchProgress(self):
  545.         return self._fetchProgress
  546.  
  547.     def getInstallProgress(self, cache):
  548.         self._installProgress._cache = cache
  549.         return self._installProgress
  550.  
  551.     def getOpCacheProgress(self):
  552.         return self._opCacheProgress
  553.  
  554.     def getCdromProgress(self):
  555.         return self._cdromProgress
  556.  
  557.     def updateStatus(self, msg):
  558.         #self.window_main.label_status.setText("%s" % msg)
  559.         print "updateStatus: " + msg
  560.         self.window_main.label_status.setText(unicode(msg, 'UTF-8'))
  561.  
  562.     def hideStep(self, step):
  563.         image = getattr(self.window_main,"image_step%i" % step)
  564.         label = getattr(self.window_main,"label_step%i" % step)
  565.         image.hide()
  566.         label.hide()
  567.  
  568.     def abort(self):
  569.         step = self.prev_step
  570.         if step > 0:
  571.             image = getattr(self.window_main,"image_step%i" % step)
  572.             iconLoader = KIconLoader()
  573.             cancelIcon = iconLoader.loadIcon("cancel", KIcon.Small)
  574.             image.setPixmap(cancelIcon)
  575.             image.show()
  576.  
  577.     def setStep(self, step):
  578.         iconLoader = KIconLoader()
  579.         if self.prev_step:
  580.             image = getattr(self.window_main,"image_step%i" % self.prev_step)
  581.             label = getattr(self.window_main,"label_step%i" % self.prev_step)
  582.             okIcon = iconLoader.loadIcon("ok", KIcon.Small)
  583.             image.setPixmap(okIcon)
  584.             image.show()
  585.             ##arrow.hide()
  586.         self.prev_step = step
  587.         # show the an arrow for the current step and make the label bold
  588.         image = getattr(self.window_main,"image_step%i" % step)
  589.         label = getattr(self.window_main,"label_step%i" % step)
  590.         arrowIcon = iconLoader.loadIcon("1rightarrow", KIcon.Small)
  591.         image.setPixmap(arrowIcon)
  592.         image.show()
  593.         label.setText("<b>" + label.text() + "</b>")
  594.  
  595.     def information(self, summary, msg, extended_msg=None):
  596.         msg = "<big><b>%s</b></big><br />%s" % (summary,msg)
  597.  
  598.         dialogue = dialog_error(self.window_main)
  599.         dialogue.label_error.setText(utf8(msg))
  600.         if extended_msg != None:
  601.             dialogue.textview_error.setText(utf8(extended_msg))
  602.             dialogue.textview_error.show()
  603.         else:
  604.             dialogue.textview_error.hide()
  605.         dialogue.button_bugreport.hide()
  606.         dialogue.setCaption("Information")
  607.         iconLoader = KIconLoader()
  608.         messageIcon = iconLoader.loadIcon("messagebox_info", KIcon.Panel)
  609.         dialogue.image.setPixmap(messageIcon)
  610.         dialogue.exec_loop()
  611.  
  612.     def error(self, summary, msg, extended_msg=None):
  613.         msg="<big><b>%s</b></big><br />%s" % (summary, msg)
  614.  
  615.         dialogue = dialog_error(self.window_main)
  616.         dialogue.label_error.setText(utf8(msg))
  617.         if extended_msg != None:
  618.             dialogue.textview_error.setText(utf8(extended_msg))
  619.             dialogue.textview_error.show()
  620.         else:
  621.             dialogue.textview_error.hide()
  622.         dialogue.button_close.show()
  623.         self.app.connect(dialogue.button_bugreport, SIGNAL("clicked()"), self.reportBug)
  624.         dialogue.exec_loop()
  625.  
  626.         return False
  627.  
  628.     def confirmChanges(self, summary, changes, downloadSize, 
  629.                        actions=None, removal_bold=True):
  630.         """show the changes dialogue"""
  631.         # FIXME: add a whitelist here for packages that we expect to be
  632.         # removed (how to calc this automatically?)
  633.  
  634.         DistUpgradeView.confirmChanges(self, summary, changes, downloadSize)
  635.         msg = unicode(self.confirmChangesMessage, 'UTF-8')
  636.         self.changesDialogue = dialog_changes(self.window_main)
  637.         self.changesDialogue.treeview_details.hide()
  638.         self.changesDialogue.connect(self.changesDialogue.show_details_button, SIGNAL("clicked()"), self.showChangesDialogueDetails)
  639.         self.translate_widget_children(self.changesDialogue)
  640.         self.changesDialogue.show_details_button.setText(_("Details") + " >>>")
  641.         self.changesDialogue.resize(self.changesDialogue.sizeHint())
  642.  
  643.         if actions != None:
  644.             cancel = actions[0].replace("_", "")
  645.             self.changesDialogue.button_cancel_changes.setText(cancel)
  646.             confirm = actions[1].replace("_", "")
  647.             self.changesDialogue.button_confirm_changes.setText(confirm)
  648.  
  649.         summaryText = unicode("<big><b>%s</b></big>" % summary, 'UTF-8')
  650.         self.changesDialogue.label_summary.setText(summaryText)
  651.         self.changesDialogue.label_changes.setText(msg)
  652.         # fill in the details
  653.         self.changesDialogue.treeview_details.clear()
  654.         self.changesDialogue.treeview_details.setColumnText(0, "Packages")
  655.         for rm in self.toRemove:
  656.             self.changesDialogue.treeview_details.insertItem( QListViewItem(self.changesDialogue.treeview_details, _("Remove %s") % rm) )
  657.         for inst in self.toInstall:
  658.             self.changesDialogue.treeview_details.insertItem( QListViewItem(self.changesDialogue.treeview_details, _("Install %s") % inst) )
  659.         for up in self.toUpgrade:
  660.             self.changesDialogue.treeview_details.insertItem( QListViewItem(self.changesDialogue.treeview_details, _("Upgrade %s") % up) )
  661.         res = self.changesDialogue.exec_loop()
  662.         if res == QDialog.Accepted:
  663.             return True
  664.         return False
  665.  
  666.     def showChangesDialogueDetails(self):
  667.         if self.changesDialogue.treeview_details.isVisible():
  668.             self.changesDialogue.treeview_details.hide()
  669.             self.changesDialogue.show_details_button.setText(_("Details") + " >>>")
  670.         else:
  671.             self.changesDialogue.treeview_details.show()
  672.             self.changesDialogue.show_details_button.setText("<<< " + _("Details"))
  673.         self.changesDialogue.resize(self.changesDialogue.sizeHint())
  674.  
  675.     def askYesNoQuestion(self, summary, msg, default='No'):
  676.         restart = QMessageBox.question(self.window_main, unicode(summary, 'UTF-8'), unicode("<font>") + unicode(msg, 'UTF-8'), QMessageBox.Yes, QMessageBox.No)
  677.         if restart == QMessageBox.Yes:
  678.             return True
  679.         return False
  680.  
  681.     def processEvents(self):
  682.         KApplication.kApplication().processEvents()
  683.  
  684.     def on_window_main_delete_event(self):
  685.         text = _("""<b><big>Cancel the running upgrade?</big></b>
  686.  
  687. The system could be in an unusable state if you cancel the upgrade. You are strongly advised to resume the upgrade.""")
  688.         text = text.replace("\n", "<br />")
  689.         cancel = QMessageBox.warning(self.window_main, _("Cancel Upgrade?"), text, QMessageBox.Yes, QMessageBox.No)
  690.         if cancel == QMessageBox.Yes:
  691.             return True
  692.         return False
  693.  
  694.  
  695.  
  696. if __name__ == "__main__":
  697.  
  698.   view = DistUpgradeViewKDE()
  699.  
  700.   cache = apt.Cache()
  701.   for pkg in sys.argv[1:]:
  702.     if cache[pkg].isInstalled and not cache[pkg].isUpgradable: 
  703.       cache[pkg].markDelete(purge=True)
  704.     else:
  705.       cache[pkg].markInstall()
  706.   cache.commit(view._fetchProgress,view._installProgress)
  707.  
  708.   # keep the window open
  709.   while True:
  710.       KApplication.kApplication().processEvents()
  711.